{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

-----------------------------------------------------------------------------
--  group.hs : the modern algebraic group 
--
--  A group looks like this {G, e, *}
--    G is a set of symbols
--    u is a special symbol called the unit symbol
--    * is a binary operator

--  Here we concern ourselves only with numeric groups.  Taking the view of 
--  a group as a set with additional structure, each group here is the 
--  subset of a numeric field (R, Q, C, Z ...) that may be generated by a 
--  pure function.  In this case a composition of lift, succ, order and u 
--  may generate the entire group
-----------------------------------------------------------------------------

module Group (

	Number(..), OpType(..), Order(..), Group(..),
    table, tableIO
    
	) where

data Number = Natural | Integer | Real

data OpType = Additive | Multiplicative | Compositional

data Order =  Order Integer | Infinity
instance Eq Order where	
    (==) (Order a) (Order b) = a == b
    (==) (Order a) Infinity = False
    (==) Infinity (Order b) = False
    (==) Infinity Infinity = True
instance Show Order where
    show (Order a) = show a
    show (Infinity) = show "inifinity"

class Show (m a) => Group g m a | g -> m a, m a -> g where
	lift :: g -> a -> m a
	suc :: m a -> m a
	order :: g -> Order
	u :: g -> m a
	gen :: g -> [m a]
	op :: m a -> m a -> m a

-----------------------------------------------------------------------------
--
--                          Group Functions
--
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--                          Table Generation
--
-- a set of functions that creates a text table represntation of a finite 
--   group that looks like the following for integers
--
--  + | 0 | 1 | 2 | 3 |
--  -------------------
--  0 | 0   1   2   3
--  1 | 1   2   3   0
--  2 | 2   3   0   1
--  3 | 3   0   1   2
--
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
-- top level function for table generation
table ::(Group g m a) => g ->String
table g = tablify g (order g)

-----------------------------------------------------------------------------
-- here we are concerned with determining whether or not the group is 
-- 	infinite, if so we don't want to make a table for it
tablify ::(Group g m a) =>g ->Order ->String
tablify g Infinity = "Sorry no dice on the infinite table ..."
tablify g (Order o) = "\n" ++ 
                      tableHead g ++ "\n" ++
                      tableSep o ++ "\n" ++
                      tableRows g ++ "\n"

-----------------------------------------------------------------------------
-- generate the head of the table
tableHead ::(Group g m a) =>g ->String
tableHead g = " + |" ++  (foldl (++) [] $
                                  map (\x ->" " ++ (show x) ++ " |")
                                      (gen g) )
-----------------------------------------------------------------------------
-- generate the separtor between the head and body of the table
tableSep ::Integer ->String
tableSep 0 = "----"
tableSep i = "----" ++ tableSep (i-1)

-----------------------------------------------------------------------------
-- generate one row of the table
tableRow ::(Group g m a) =>g ->m a ->String
tableRow g m = " " ++ (show m) ++ " |"  ++ 
             (foldl (++) [] $
                 map (\x ->" " ++ (show (m `op` x)) ++ "  ")
                     (gen g) ) ++ "\n"

-----------------------------------------------------------------------------
-- generate all rows of the table
tableRows ::(Group g m a) =>g ->String
tableRows g = foldl (++) [] $
                   map (tableRow g) (gen g)

-----------------------------------------------------------------------------
-- a convinence function to dump the string representation of the table out
-- 	on to the console
tableIO ::(Group g m a) =>g ->IO ()
tableIO g = putStr $ table g

